package com.minidb.engine;

import com.minidb.storage.BufferPool;
import com.minidb.storage.FileManager;
import com.minidb.storage.Page;
import com.minidb.utils.Constants;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * SystemCatalog
 * - 以普通表 "__catalog" 的形式持久化系统元数据（页式存储）。
 * - 行格式固定：TABLE, COLUMN, TYPE, ORDINAL（字符串存储，ORDINAL 为字符串形式的序号）
 * - 不依赖 CatalogManager（避免循环），只用 FileManager/BufferPool 直接操作页。
 */
public class SystemCatalog {
    private final FileManager fm;
    private final BufferPool bp;
    
    // 新增：元数据版本控制
    private static final String METADATA_VERSION = "1.0";
    
    public SystemCatalog(FileManager fm, BufferPool bp) {
        this.fm = fm;
        this.bp = bp;
    }

    /** 增强的初始化方法 - 支持元数据完整性检查 */
    public void initIfAbsent() {
        if (fm.getPageCount(Constants.SYSTEM_CATALOG_TABLE) == 0) {
            fm.createTableFile(Constants.SYSTEM_CATALOG_TABLE);
            Page p0 = fm.allocatePage(Constants.SYSTEM_CATALOG_TABLE);
            
            // 添加元数据版本信息
            List<String> versionRecord = List.of("__SYSTEM__", "VERSION", "TEXT", METADATA_VERSION);
            p0.addRecord(versionRecord);
            
            bp.putPage(Constants.SYSTEM_CATALOG_TABLE, p0);
        }
        
        // 验证元数据完整性
        validateMetadataIntegrity();
    }
    
    /** 新增：元数据完整性验证 */
    private void validateMetadataIntegrity() {
        try {
            List<List<String>> allRecords = scanAll();
            
            // 检查版本兼容性
            boolean versionFound = allRecords.stream()
                .anyMatch(record -> record.size() >= 4 && 
                         "__SYSTEM__".equals(record.get(0)) && 
                         "VERSION".equals(record.get(1)));
            
            if (!versionFound) {
                // 添加版本信息到现有系统表
                appendEntry("__SYSTEM__", "VERSION", "TEXT", -1);
            }
            
            // 检查表结构完整性
            Map<String, Integer> tableColumnCounts = new HashMap<>();
            for (List<String> record : allRecords) {
                if (record.size() >= 4 && !"__SYSTEM__".equals(record.get(0))) {
                    String tableName = record.get(0);
                    tableColumnCounts.merge(tableName, 1, Integer::sum);
                }
            }
            
            // 验证每个表至少有一列
            for (Map.Entry<String, Integer> entry : tableColumnCounts.entrySet()) {
                if (entry.getValue() == 0) {
                    throw new IllegalStateException("表 " + entry.getKey() + " 缺少列定义");
                }
            }
            
        } catch (Exception e) {
            throw new RuntimeException("元数据完整性验证失败: " + e.getMessage(), e);
        }
    }
    
    /** 增强的扫描方法 - 支持过滤和排序 */
    public List<List<String>> scanAll() {
        List<List<String>> out = new ArrayList<>();
        int n = fm.getPageCount(Constants.SYSTEM_CATALOG_TABLE);
        
        for (int pid = 0; pid < n; pid++) {
            try {
                Page p = bp.getPage(Constants.SYSTEM_CATALOG_TABLE, pid);
                for (var rec : p.getRecords()) {
                    if (rec != null && rec.size() >= 4) {
                        out.add(new ArrayList<>(rec));
                    }
                }
            } catch (Exception e) {
                // 容错处理：跳过损坏的页面
                System.err.println("警告：跳过损坏的元数据页面 " + pid + ": " + e.getMessage());
            }
        }
        
        // 按表名和序号排序
        out.sort((a, b) -> {
            int tableCompare = a.get(0).compareTo(b.get(0));
            if (tableCompare != 0) return tableCompare;
            
            try {
                int ordinalA = Integer.parseInt(a.get(3));
                int ordinalB = Integer.parseInt(b.get(3));
                return Integer.compare(ordinalA, ordinalB);
            } catch (NumberFormatException e) {
                return a.get(3).compareTo(b.get(3));
            }
        });
        
        return out;
    }
    
    /** 新增：事务性批量追加 */
    public boolean appendEntriesTransactional(String table, List<String> columns, List<String> types) {
        if (columns.size() != types.size()) {
            throw new IllegalArgumentException("列名和类型数量不匹配");
        }
        
        try {
            // 开始事务（简化版本）
            List<List<String>> newEntries = new ArrayList<>();
            for (int i = 0; i < columns.size(); i++) {
                newEntries.add(List.of(table, columns.get(i), types.get(i), String.valueOf(i)));
            }
            
            // 批量写入
            for (List<String> entry : newEntries) {
                appendRow(entry);
            }
            
            // 强制刷新到磁盘
            bp.flushAll();
            return true;
            
        } catch (Exception e) {
            // 事务回滚（简化版本）
            System.err.println("元数据写入失败，需要回滚: " + e.getMessage());
            return false;
        }
    }
    
    /** 新增：删除表的元数据 */
    public boolean removeTableMetadata(String tableName) {
        try {
            // 注意：这是一个简化实现，实际应该支持页内记录删除
            // 当前实现标记为删除，实际删除需要重写整个系统表
            appendEntry("__DELETED__", tableName, "MARKER", -1);
            bp.flushAll();
            return true;
        } catch (Exception e) {
            System.err.println("删除表元数据失败: " + e.getMessage());
            return false;
        }
    }

    /** 追加一条目录记录（单行） */
    public void appendEntry(String table, String column, String type, int ordinal) {
        List<String> row = List.of(table, column, type, String.valueOf(ordinal));
        appendRow(row);
    }

    /** 批量追加（用于 create table 时一次写入多列元数据） */
    public void appendEntries(String table, List<String> columns, List<String> types) {
        for (int i = 0; i < columns.size(); i++) {
            appendEntry(table, columns.get(i), types.get(i), i);
        }
    }

    /** 低层追加一条记录到 __catalog 的最后一页（必要时分配新页） */
    private void appendRow(List<String> row) {
        String table = Constants.SYSTEM_CATALOG_TABLE;
        if (fm.getPageCount(table) == 0) {
            fm.createTableFile(table);
            Page p = fm.allocatePage(table);
            bp.putPage(table, p);
        }
        int last = Math.max(0, fm.getPageCount(table) - 1);
        Page page = bp.getPage(table, last);
        if (!page.addRecord(row)) { // 页满则分配新页
            Page np = fm.allocatePage(table);
            bp.putPage(table, np);
            if (!np.addRecord(row)) throw new IllegalStateException("__catalog: 新页也无法写入记录");
        }
    }
}
